package com.linkedin.dagli.annotation.visitor;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * {@link VisitedBy} provides a way to quickly create a visitor interface implementing the "visitor pattern", with
 * a "visit" method for each annotated class that returns a value (whose type is determined by a type parameter on the
 * visitor interface) when passed an instance of that class.
 *
 * The generated interface will be public (use the {@link Visitor package annotation to make it package-private)} and no
 * interface with the same name can already exist.  Due to limitations of annotation processing, {@link VisitedBy}
 * should not be used to attempt to create visitors for classes across multiple modules, and should not be used to
 * create visitors for classes that are themselves generated by annotation processing.
 *
 * If this annotation is applied to a {@link com.linkedin.dagli.annotation.struct.Struct} definition, the resulting
 * {@code @Struct} (rather than the class defining the {@code @Struct}) will be added to the visitor interface, and
 * an appropriate accept() method will be automatically generated.  If there exists a non-private, non-static
 * accept(...) method that takes a single argument in the {@code @Struct} definition, a class it extends, or an
 * interface it implements, the annotation processor will assume the new accept(...) method overrides it and match its
 * visibility.  If multiple such methods exists, which method's visibility is matched is arbitrary.
 */
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE})
public @interface VisitedBy {
  /**
   * The package and class name for the visitor interface that will be generated with a visit(...) method corresponding
   * to the annotated class.  A value of "com.xyz.SomeVisitor" will result in an interface called "SomeVisitor" being
   * generated in the "com.xyz" package.  If the package is omitted (e.g. just the value "SomeClass" is provided) the
   * class will be generated in the current package.
   *
   * @return the package and class name for the visitor interface that will be generated
   */
  String value();

  /**
   * If true, a default implementation for the visit() method for the annotation class will be created that throws
   * {@link UnsupportedOperationException}.  If false (the default), no default implementation will be created.
   *
   * @return whether or not to add a default, exception-throwing implementation for the created visit method
   */
  boolean throwIfUnimplemented() default false;
}
